package milkyway.hightech.customergui;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Desktop;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import java.io.IOException;

import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;

import java.net.URI;

import java.net.URISyntaxException;

import java.util.HashMap;
import java.util.Map;
import java.util.Observable;
import java.util.Observer;
import java.util.ResourceBundle;
import java.util.logging.Logger;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;

import milkyway.hightech.customer.BankCustomerView;
import milkyway.hightech.exceptions.EmptyInputException;
import milkyway.hightech.exceptions.SystemNotAvailableException;
import milkyway.hightech.money.Currency;

/**
 *
 * @author michael
 */
public class CustomerGUI extends JFrame implements ActionListener, Observer
{
    private CustomerGUIController controller;
    private ResourceBundle rb;

    private JPanel activityPanel = new JPanel();
    private JButton okButton = new JButton("OK");
    private JButton backButton = new JButton("BACK");
    private JLabel messageLabel = new JLabel("Messages to display");

    private String methodName;

    private static Logger logger =
        Logger.getLogger(CustomerGUI.class.getName());

    /**
     *
     * @param bank
     * @param rb
     * @param bankName
     */
    public CustomerGUI(BankCustomerView bank, ResourceBundle rb, String bankName)
    {
        this.controller = new CustomerGUIController(bank, rb);
        this.rb = rb;

        this.setTitle(bankName);
        this.setSize(800, 600);
        this.setVisible(true);
        this.setLayout(new BorderLayout());

        CustomerGUIMenu menu = new CustomerGUIMenu(rb);
        menu.addObserver(this);

        this.add(menu.getMenu(), BorderLayout.WEST);
        this.add(activityPanel, BorderLayout.CENTER);
        this.add(messageLabel, BorderLayout.SOUTH);
        this.pack();

        okButton.setName("ok");
        okButton.addActionListener(this);

        backButton.setName("back");
        backButton.addActionListener(this);
    }

    /**
     *
     * @param o
     * @param obj
     */
    @Override
    public void update(Observable o, Object obj)
    {
        try
        {
            changeActivityPanel(obj.toString());
        }

        catch (ClassNotFoundException ex)
        {
            logger.severe(ex.getMessage());
        }

        catch (InstantiationException ex)
        {
            logger.severe(ex.getMessage());
        }

        catch (IllegalAccessException ex)
        {
            logger.severe(ex.getMessage());
        }
    }

    /**
     * changes the panel for the specific method.
     * @param methodName the name of the method for which the panel and the
     * elements should be generated.
     * @throws ClassNotFoundException
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    public void changeActivityPanel(String methodName)
        throws ClassNotFoundException, InstantiationException,
            IllegalAccessException
    {
        this.methodName = methodName;

        this.remove(activityPanel);
        activityPanel = createActivityPanel();
        this.add(BorderLayout.CENTER, activityPanel);
        this.pack();
    }

    /**
     *
     * @return the panel for the specific method
     * @throws ClassNotFoundException
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    private JPanel createActivityPanel() throws ClassNotFoundException,
        InstantiationException, IllegalAccessException
    {
        int row = 0;

        JPanel formPanel = new JPanel(new GridLayout(0, 1));
        formPanel.setPreferredSize(new Dimension(600, 600));

        Map<String, String[]> map =
            (HashMap<String, String[]>)rb.getObject("formElementValues");

        Class<?>[] params = controller.getParams(methodName);

        for (int i = 0; i < params.length; i++)
        {
            JLabel label = new JLabel(map.get(methodName)[i + 1]);
            formPanel.add(label, row++);

            if (params[i].isEnum())
            {
                String currency = "milkyway.hightech.money.Currency";
                JComboBox box = new JComboBox();
                Object[] o = params[i].getEnumConstants();

                for (int j = 0; j < o.length; j++)
                    box.addItem(o[j]);

                if (params[i].equals(Class.forName(currency)))
                {
                    String value = rb.getObject("currency").toString();
                    box.setSelectedIndex(Currency.valueOf(value).ordinal());
                }

                formPanel.add(box, row++);
            }

            else
            {
                JTextField text = new JTextField();
                text.setPreferredSize(new Dimension(100, 21));
                formPanel.add(text, row++);
            }
        }

        formPanel.add(okButton, row++);
        formPanel.add(backButton, row);

        return formPanel;
    }

    /**
     * executed if the OK- or Backbutton was clicked.
     * @param e
     */
    @Override
    public void actionPerformed(ActionEvent e)
    {
        try
        {
            if (((JButton)e.getSource()).getName().equals("back"))
            {
                this.remove(activityPanel);
                this.pack();
            }

            else if (proofInput(activityPanel.getComponents()))
            {
                try
                {
                    Component[] comp = activityPanel.getComponents();
                    Object result = controller.execute(methodName, comp);

                    String message = rb.getObject("information").toString();
                    String fileName = "";
                    int messageType = JOptionPane.INFORMATION_MESSAGE;
                    int optionType = JOptionPane.DEFAULT_OPTION;
                    
                    if(methodName.equals("getAccountStatement"))
                        optionType = JOptionPane.YES_NO_OPTION;
                    
                    if(result.getClass().isArray())
                    {
                        fileName = Array.get(result, 1).toString();
                        result = Array.get(result, 0);
                    }
                    
                    Object res = showMessage(message, result.toString(),
                        messageType, optionType);
                    
                    if(methodName.equals("getAccountStatement")
                       && res.equals(0))
                    {
                        try
                        {
                            URI uri = new URI(fileName);
                            Desktop.getDesktop().browse(uri);
                        }
                        catch (IOException f)
                        {
                            throw new SystemNotAvailableException();
                        }
                        catch (URISyntaxException f)
                        {
                            throw new SystemNotAvailableException();
                        }
                    }
                }

                catch (IllegalAccessException ex)
                {
                    logger.severe(ex.getMessage());

                    Object message = rb.getObject("systemNotAvailable");
                    throw new SystemNotAvailableException(message.toString());
                }

                catch (InvocationTargetException ex)
                {
                    logger.severe(ex.getMessage());

                    String message = ex.getCause().getMessage();
                    throw new SystemNotAvailableException(message);
                }

                catch (EmptyInputException ex)
                {
                    logger.severe(ex.getMessage());

                    throw new SystemNotAvailableException(ex.getMessage());
                }

                catch (ClassNotFoundException ex)
                {
                    logger.severe(ex.getMessage());

                    String message = rb.getString("systemNotAvailable");
                    throw new SystemNotAvailableException(message);
                }
            }
        }

        catch (SystemNotAvailableException ex)
        {
            messageLabel.setText(ex.getMessage());

            String message = rb.getObject("errorMessageTitel").toString();
            int messageType = JOptionPane.ERROR_MESSAGE;
            int optionType = JOptionPane.OK_OPTION;
            showMessage(message, ex.getMessage(), messageType, optionType);
        }
    }

    /**
     *
     * @param titel
     * @param message
     * @param messageType
     * @param optionType
     * @return
     */
    private Object showMessage(String titel, String message,
        int messageType, int optionType)
    {
        messageLabel.setText(message);
        JOptionPane optionPane = new JOptionPane(message, messageType, optionType);
        
        JDialog dialog = optionPane.createDialog(titel);
        dialog.show();
        
        return optionPane.getValue();
    }

    /**
     * proofs the userinput
     * @param components
     * @return true if the input was correct
     */
    private boolean proofInput(Component[] components)
    {
        int paramCount = 0;
        boolean inputOK = true;
        Class<?>[] clazz = controller.getParams(methodName);

        for (int i = 0; i < components.length - 2; i++)
        {
            if (components[i] instanceof JTextField)
            {
                try
                {
                    String stringClass = "java.lang.String";
                    String intClass = "java.lang.Integer";
                    String bigIntClass = "java.math.BigInteger";

                    Component co = components[i];
                    JTextField t = (JTextField)co;
                    char[] c = t.getText().toCharArray();

                    if (clazz[paramCount].equals(Class.forName(stringClass)))
                    {
                        for (int j = 0; j < c.length; j++)
                        {
                            if (!('a' <= c[j] && c[j] <= 'z' || c[j] == ' ' ||
                                  'A' <= c[j] && c[j] <= 'Z'))
                            {
                                Component comp = activityPanel.getComponent(i);
                                JTextField text = (JTextField)comp;

                                text.setText(rb.getString("stringInputError"));
                                inputOK = false;
                            }
                        }
                    }

                    else if (clazz[paramCount].equals(Class.forName(intClass)) ||
                             clazz[paramCount].equals(Class.forName(bigIntClass)))
                    {
                        for (int j = 0; j < c.length; j++)
                        {
                            if (!('0' <= c[j] && c[j] <= '9'))
                            {
                                Component comp = activityPanel.getComponent(i);
                                JTextField text = (JTextField)comp;

                                text.setText(rb.getString("intInputError"));
                                inputOK = false;
                            }
                        }
                    }
                }

                catch (ClassNotFoundException ex)
                {
                    logger.severe(ex.getMessage());
                }

                paramCount++;
            
            }
            
            else if (components[i] instanceof JComboBox)
            {
                paramCount++;
            }
        }

        return inputOK;
    }
}
